package JUC.第04章_锁;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 公平锁/非公平锁
 *
 * 公平锁是指多个线程按照申请锁的顺序来获取锁。
 * 非公平锁是指多个线程获取锁的顺序并不是按照申请锁的顺序，有可能后申请的线程比先申请的线程优先获取锁。
 *      有可能，会造成优先级反转或者饥饿现象。
 * 对于Java ReentrantLock而言，通过构造函数指定该锁是否是公平锁，默认是非公平锁。
 *      非公平锁的优点在于吞吐量比公平锁大。
 * 对于Synchronized而言，也是一种非公平锁。
 *      由于其并不像ReentrantLock是通过AQS的来实现线程调度，所以并没有任何办法使其变成公平锁。
 *
 * 如果为了更高的吞吐量，很显然非公平锁是比较合适的，因为节省很多线切换时间，
 * 吞吐量自然就上去了;
 * 否则那就用公平锁，大家公平使用。
 * 公平锁   在抢占资源时  会逐渐的趋于公平
 */
public class B3_公平锁和非公平锁 {
    //一种 //在高内聚低耦合的前提下  线程  操作  资源类
    // 资源类自带的方法     synchronized重锁   lock轻锁   //函数式接口可用
    public static void main(String[] args) {
        //公平锁 抢夺的个数几乎是平均的，得到锁的概率都差不多
        //非公平锁 会存在有些线程常占用锁
        Ticket ticket=new Ticket(true);//true:公平锁    false：非公平锁
        new Thread(() ->{for(int i=0;i<40;i++)ticket.sale();},"A").start();
        new Thread(() ->{for(int i=0;i<40;i++)ticket.sale();},"B").start();
        new Thread(() ->{for(int i=0;i<40;i++)ticket.sale();},"C").start();
    }
}
class Ticket {
    Lock lock;//可重入锁 //默认 false  非公平锁
    private int number = 30 ; //volatile  在不加锁的时候可保证唯一性

    public Ticket(boolean fair){
        lock = new ReentrantLock(fair);//可重入锁 //默认 false  非公平锁
    }
    //高内聚 资源类自带的方法     synchronized重锁   lock轻锁   //函数式接口可用
    public  void sale() {
        lock.lock();//加锁
        try{
            if(number>0){
                try {TimeUnit.MILLISECONDS.sleep(30); } catch (InterruptedException e) {e.printStackTrace();}
                System.out.println(Thread.currentThread().getName()+"\t卖出第："+(number--)+"张票"+"还剩下："+number);
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();//放锁
        }
    }

}//资源类      =实例+方法

